package com.ruoyi.cs.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.Response;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.common.utils.pay.*;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.cs.domain.*;
import com.ruoyi.cs.mapper.TBalanceChangeMapper;
import com.ruoyi.cs.mapper.TRechargeMapper;
import com.ruoyi.cs.mapper.TUserMapper;
import com.ruoyi.cs.mapper.TUserSyMapper;
import com.ruoyi.cs.service.CommonService;
import com.ruoyi.cs.service.ICHPayService;
import com.ruoyi.system.mapper.SysConfigMapper;
import com.ruoyi.system.mapper.SysDictDataMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.util.*;
/**
 * 传化支付
 */
@Service
@SuppressWarnings("ALL")
public class CHPayServiceImpl implements ICHPayService {

    private static final Logger log = LoggerFactory.getLogger(CHPayServiceImpl.class);

    @Value("${ruoyi.chpayNotify}")
    private String chpayNotify;

    @Value("${ruoyi.picpath}")
    private String picpath;

    @Value("${ruoyi.profile}")
    private String profile;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private TUserMapper userMapper;

    @Autowired
    private CommonService commonService;

    @Autowired
    private SysDictDataMapper sysDictDataMapper;

    @Autowired
    private SysConfigMapper sysConfigMapper;

    @Autowired
    private TRechargeMapper tRechargeMapper;

    @Autowired
    private TUserSyMapper tUserSyMapper;

    @Autowired
    private TBalanceChangeMapper tBalanceChangeMapper;


    @Override
    public Response<Map> chRecharge(String userId, BigDecimal czMoney, String czEquipment) throws Exception {

        TUser tUser = userMapper.selectTUserById(userId);

        BigDecimal giveFee = new BigDecimal("0");
        try {
            giveFee = commonService.rechargeVerification(tUser, czMoney);
        } catch (Exception e) {
            return Response.fail(e.getMessage());
        }

        String out_trade_no = DateUtils.dateTimeNow() + IdUtils.fastUUID().substring(0, 8);
        /*单位:分*/
        BigDecimal fee = czMoney.multiply(new BigDecimal(6.5)).setScale(2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
        TreeMap<String, String> treeMap = buildDoPay(out_trade_no, String.valueOf(fee.intValue()), chpayNotify);
        String resStr = HttpUtils.http(CHPayConfig.unifiedorder, treeMap);
        log.info("传化支付请求支付pc接口响应:{},参数:{}", resStr, treeMap);
        /*String sign = buildSign(treeMap,CHPayConfig.key);*/
        JSONObject result = null;
        String picurl = null;
        if (resStr != null) {
            result = JSON.parseObject(resStr);
            String returnCode = result.getString("return_code");
            if (Constants.SUCCESS.equals(returnCode)) {
                JSONObject signObj = result.getJSONObject("params_info");
                String sign = result.getString("sign");
                String payInfo = signObj.getString("pay_info");
                String paramsStr = SignUtils.getSortJson(signObj);
                String mchSign = SignUtils.buildStrSign(paramsStr, CHPayConfig.key);
                /*校验签名*/
                if (mchSign.equals(sign)) {
                    try {
                        /**生产二维码图片*/
                        picurl = commonService.scQrCodeImge(payInfo);
                    } catch (Exception e) {
                        log.error("传化支付生产二维码订单异常:{}", e.getMessage());
                        e.printStackTrace();
                        return Response.fail("发送请求失败");
                    }
                    TRecharge tRecharge = new TRecharge();
                    tRecharge.setUserId(userId);
                    tRecharge.setCzId(out_trade_no);
                    tRecharge.setDelFlag(Constants.SUCCESS);
                    tRecharge.setCzType(Constants.ALIPAY);
                    /**支付结果  0 待充值 1充值成功 2充值失败*/
                    tRecharge.setCzStatus(Constants.CZSTATUS0);
                    /**交易类型*/
                    tRecharge.setCzEquipment(czEquipment);
                    tRecharge.setCreateTime(DateUtils.getNowDate());
                    tRecharge.setGiveFee(giveFee);
                    tRecharge.setCzMoney(czMoney);
                    tRecharge.setCzPlatform(Constants.CZPLATFORM2);
                    tRecharge.setUserType(tUser.getUserType());
                    if (StringUtils.isNotEmpty(tUser.getUserPromotersId())) {
                        tRecharge.setUserPromotersId(tUser.getUserPromotersId());
                    }
                    int count = tRechargeMapper.insertTRecharge(tRecharge);
                    if (count > 0) {
                        Map map = new HashMap();
                        map.put("picUrl", picurl);
                        map.put("czId", out_trade_no);
                        map.put("totalFee", czMoney);
                        map.put("url", payInfo);
                        log.info("传化支付订单生产：参数信息：{}，支付金额：{},订单号：{}", JSON.toJSONString(tRecharge), fee, out_trade_no);
                        return Response.success(map);
                    } else {
                        log.error("传化支付充值记录表插入失败：参数信息：{}，支付金额：{},订单号：{}", JSON.toJSONString(tRecharge), fee, out_trade_no);
                        return Response.fail("充值窗口异常，请联系管理员处理!");
                    }
                } else {
                    log.error("传化支付下单验签失败,传化响应签名:{},校验生成签名：{}", sign, mchSign);
                    return Response.fail("签名校验失败，请刷新后重试！");
                }
            } else {
                log.error("传化支付请求支付接口响应失败信息:{}", result);
                return Response.fail("支付接口响应失败，请刷新后再试一次吧！");
            }
        } else {
            log.error("传化支付请求支付接口响应为空,响应参数:{}", result);
            return Response.fail("支付接口响应异常，请刷新后重试！");
        }
    }

    /**
     * 异步通知接口
     *
     * @param request
     * @param response
     * @return
     */
    @Override
    public void chPayNotify(HttpServletRequest request, HttpServletResponse response) {
        PrintWriter out = null;
        try {
            out = response.getWriter();
            response.setCharacterEncoding("utf-8");
            request.setCharacterEncoding("utf-8");
            String mch_id = request.getParameter("mch_id");
            String order_no = request.getParameter("order_no");
            String total_fee = request.getParameter("total_fee");
            String order_status = request.getParameter("order_status");
            String order_status_desc = request.getParameter("order_status_desc");
            String out_trade_no = request.getParameter("out_trade_no");
            String pay_time = request.getParameter("pay_time");
            String trade_type = request.getParameter("trade_type");
            String sign = request.getParameter("sign");
            String body = request.getParameter("body");

            log.info("异步回调返回参数： mch_id:{},order_no:{},total_fee:{}，order_status:{}，order_status_desc:{}，out_trade_no:{}，pay_time:{}，trade_type:{}，sign:{}，body:{}",
                    mch_id,order_no,total_fee,order_status,order_status_desc,out_trade_no,pay_time,trade_type,sign,body);

            final TreeMap<String, String> paramsMap = new TreeMap<String, String>();
            paramsMap.put("mch_id", mch_id);
            paramsMap.put("order_no", order_no);
            paramsMap.put("out_trade_no", out_trade_no);
            paramsMap.put("total_fee", total_fee);
            paramsMap.put("trade_type", trade_type);
            paramsMap.put("order_status", order_status);
            paramsMap.put("order_status_desc", order_status_desc);
            paramsMap.put("body", body);
            paramsMap.put("pay_time", pay_time);

            String mchSign = SignUtils.buildMapSign(paramsMap, CHPayConfig.key);
            paramsMap.put("sign",sign);
            paramsMap.put("自己生成mchSign",mchSign);
            String paramStr = JSON.toJSONString(paramsMap);
            if (mchSign.equals(sign)) {
                // 验签通过，这里修改订单状态
                TRecharge tRecharge = tRechargeMapper.selectTRechargeById(out_trade_no);
                if (tRecharge != null) {
                    /*成功状态*/
                    if (order_status.equals(Constants.AUDITSTATUS2)) {
                        if (tRecharge.getCzStatus().equals(Constants.CZSTATUS0)) {
                            commonService.czSuccessHandle(tRecharge,out_trade_no,order_no,paramStr);
                        } else {
                            log.info("用户充值操作已完成,无需重复操作。充值ID:{},充值状态:{}",tRecharge.getCzId(),tRecharge.getCzStatus());
                        }
                    } else {
                        if (tRecharge.getCzStatus().equals(Constants.CZSTATUS0)) {
                            commonService.czFailHandle(tRecharge,out_trade_no,order_no,paramStr);
                        }
                    }
                    out.write("SUCCESS");
                } else {
                    log.error("查询充值订单信息为空,请求参数：{}",paramStr);
                }
                out.write("SUCCESS");
            } else {
                out.write("FAIL");
                log.error("传化充值异步通知验签失败，参数：{}",paramStr);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("异步回调异常：{},", e.getMessage());
            out.write("FAIL");
        } finally {
            out.flush();
            out.close();
        }
    }

    /*组装支付参数*/
    private static TreeMap<String, String> buildDoPay(String orderid, String czMoney, String chpayNotify) {
        TreeMap<String, String> map = new TreeMap<String, String>();
        map.put("mch_id", CHPayConfig.mch_id);   //1必填 商户号
        map.put("body", CHPayConfig.COMMODITY_NAME);     //2必填 商品名称
        map.put("trade_type", CHPayConfig.TRADE_TYPE_ALIPAY_FTF);// 3必填
        map.put("total_fee", czMoney); //4必填 支付金额 分为单位
        map.put("out_trade_no", orderid);  //5交易单号
        map.put("notify_url", chpayNotify);                 //6必填 回调通知地址；
        map.put("return_url", "https://b5skins.com/");              //7非必填  交易成功返回地址 ALIPAY.WEB的时需要
        map.put("sign", buildSign(map, CHPayConfig.key));  //8必填 签名
        return map;
    }

    /**
     * 生成签名字段
     *
     * @param map
     * @return
     */
    private static String buildSign(TreeMap<String, String> map, String key) {
        Map<String, String> params = SignUtils.paraFilter(map);
        StringBuilder buf = new StringBuilder((params.size() + 1) * 10);
        SignUtils.buildPayParams(buf, params, false);
        String preStr = buf.toString();
        String sign = MD5.sign(preStr, "&key=" + key, "utf-8");
        return sign;
    }
}
